package com.naman14.androidlame;

import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * Create by renxianzuo on 2021/5/13
 * Describe
 */
public class AndroidLameRecorder {
    private int mVolumeLevel = 1;
    private OnLogLameListener onLogLameListener;
    private OnRecordStatusLameListener onRecordStatusLameListener;
    private int minBuffer;
    private int inSamplerate = 8000;

    private boolean isRecording = false;

    private short[] buffer;
    private byte[] mp3buffer;
    private AudioRecord audioRecord;
    private AndroidLame androidLame;
    private FileOutputStream outputStream;

    public void setOnLogLameListener(OnLogLameListener onLogLameListener) {
        this.onLogLameListener = onLogLameListener;
    }

    public void setOnRecordStatusLameListener(OnRecordStatusLameListener onRecordStatusLameListener) {
        this.onRecordStatusLameListener = onRecordStatusLameListener;
    }

    public AndroidLameRecorder() {
    }

    /**
     * 开始路径
     *
     * @param filePath
     */
    public void startRecording(String filePath) {
        isRecording = true;

        minBuffer = AudioRecord.getMinBufferSize(inSamplerate, AudioFormat.CHANNEL_IN_MONO,
                AudioFormat.ENCODING_PCM_16BIT);

        printLog("Initialising audio recorder..");
        audioRecord = new AudioRecord(
                MediaRecorder.AudioSource.MIC, inSamplerate,
                AudioFormat.CHANNEL_IN_MONO,
                AudioFormat.ENCODING_PCM_16BIT, minBuffer * 2);

        //5 seconds data
        printLog("creating short buffer array");
        buffer = new short[inSamplerate * 2 * 5];

        // 'mp3buf' should be at least 7200 bytes long
        // to hold all possible emitted data.
        printLog("creating mp3 buffer");
        mp3buffer = new byte[(int) (7200 + buffer.length * 2 * 1.25)];

        try {
            outputStream = new FileOutputStream(new File(filePath));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        printLog("Initialising Andorid Lame");
        androidLame = new LameBuilder()
                .setInSampleRate(inSamplerate)
                .setOutChannels(1)
                .setOutBitrate(32)
                .setOutSampleRate(inSamplerate)
                .build();
                
        printLog("started audio recording");
        if (onRecordStatusLameListener != null) {
            onRecordStatusLameListener.onStartRecording();
        }
        audioRecord.startRecording();

        int bytesRead = 0;

        while (isRecording) {

            printLog("reading to short array buffer, buffer sze- " + minBuffer);
            bytesRead = audioRecord.read(buffer, 0, minBuffer);
            printLog("bytes read=" + bytesRead);

            calculateVolume(buffer);

            if (bytesRead > 0) {

                printLog("encoding bytes to mp3 buffer..");
                int bytesEncoded = androidLame.encode(buffer, buffer, bytesRead, mp3buffer);
                printLog("bytes encoded=" + bytesEncoded);

                if (bytesEncoded > 0) {
                    try {
                        printLog("writing mp3 buffer to outputstream with " + bytesEncoded + " bytes");
                        outputStream.write(mp3buffer, 0, bytesEncoded);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        printLog("stopped recording");
//        updateStatus("Recording stopped");

        printLog("flushing final mp3buffer");
        int outputMp3buf = androidLame.flush(mp3buffer);
        printLog("flushed " + outputMp3buf + " bytes");

        if (outputMp3buf > 0) {
            try {
                printLog("writing final mp3buffer to outputstream");
                outputStream.write(mp3buffer, 0, outputMp3buf);
                printLog("closing output stream");
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        printLog("releasing audio recorder");
        audioRecord.stop();
        audioRecord.release();

        printLog("closing android lame");
        androidLame.close();

        isRecording = false;
        mVolumeLevel = 1;
        if (onRecordStatusLameListener != null) {
            onRecordStatusLameListener.onStopRecording();
        }
    }

    /**
     * 停止录音
     */
    public void stopRecording() {
        isRecording = false;
    }

    public int getVolumeLevel() {
        return mVolumeLevel;
    }

    /**
     * 录音状态 true-录音 false-停止
     *
     * @return
     */
    public boolean isRecording() {
        return isRecording;
    }

    private void printLog(String msg) {
        if (onLogLameListener != null) {
            onLogLameListener.onLogLame(msg);
        }
    }

    public interface OnLogLameListener {
        void onLogLame(String msg);
    }

    public interface OnRecordStatusLameListener {
        void onStartRecording();

        void onStopRecording();
    }

    private void calculateVolume(short[] buffer) {
        double sumVolume = 0.0;
        double avgVolume = 0.0;
        double volume = 0.0;

        for (short b : buffer) {
            sumVolume += Math.abs(b);
        }
        avgVolume = sumVolume / buffer.length;
        volume = Math.log10(1 + avgVolume) * 10;

        mVolumeLevel =  (int)Math.ceil(volume);

    }
}
